#lang planet neil/sicp
(define (even? x)
  (= (remainder x 2) 0))
(define (point x y) (cons x y))
(define (x-point p) (car p))
(define (y-point p) (cdr p))

(define (print-point p)
  (newline)
  (display "(")
  (display (x-point p))
  (display ",")
  (display (y-point p))
  (display ")")
  )

(define (midpoint-segment p1 p2)
  (cons (/ (+ (x-point p1) (x-point p2)) 2)
        (/ (+ (y-point p1) (y-point p2)) 2)))

(define p1 (point 2.0 3))
(define p2 (point 3 7.0))
;(print-point (midpoint-segment p1 p2))
(newline)

(define (t-cons x y)
  (lambda (m) (m x y)))

(define (t-car tmp-cons)
  (tmp-cons (lambda (x y) x)))
(define (t-cdr tmp-cons)
  (tmp-cons (lambda (x y) y)))
(define test-cons (t-cons 3 4))

(define (last-pair l)
  (define (iter l)
    (if (null? (cdr l))
        (car l)
        (iter (cdr l))))
  (iter l))
;(last-pair (list 2 3 5 6))

(define (length l)
  (define (iter l n)
    (if (null? l)
        n
        (iter (cdr l) (inc n))))
  (iter l 0))

(define (append src dct)
  (if (null? src)
      dct
      (cons (car src) (append (cdr src) dct))))
(define (reverse l)
  (define (pos x l)
    (define (iter n l)
      (if (= x n)
          (car l)
          (iter (inc n) (cdr l))))
    (iter 1 l))
  (define (iter n r)
    (if (= n 0)
        r
        (iter (dec n) (cons (pos n l) r))))
  (iter (length l) nil))

(define (t-reverse l)
  (define (iter r l)
    (if (null? l)
        r
        (iter (cons (car l) r) (cdr l))))
  (iter nil l))
;(reverse (list 2 3 4 5))

(define (same-parity x . y)
  (define (iter r n l)
    (cond ((= n 0) (cons r nil))
          ((= (remainder x 2) (remainder (car l) 2)) (cons r (iter (car l) (dec n) (cdr l))))
          (else (iter r (dec n) (cdr l)))))
  (iter x (length y) y))

;(same-parity 1 2 3 5 6 8 7)
(define (square x)
  (* x x))
(define (square-list items)
  (if (null? items)
      nil
      (cons (square (car items)) (square-list (cdr items)))))
(define (t-square-list items)
  (map square items))

;(append (list 1 2 3 4) (list 3))

(define (for-each func contain)
  (define (iter c)
    (if (null? c)
        nil
        (cons (func (car c)) (iter (cdr c)))))
  (iter contain))

;(for-each square (list 2 3 4 5))
;(cons (list 1 2 3) (list 3 4))
;(list (list 1 2 3) (list 3 4))
;(list 1 2 3)

(define (deep-reverse src)
  (if (null? src)
      nil
      (append (deep-reverse (cdr src))
              (if (pair? (car src))
                  (list (deep-reverse (car src)))
                  (list (car src))))))
(define (m-deep-reverse src)
  (define (iter r c)
    (if (null? c)
        r
        (iter (cons (if (pair? (car c))
                        (m-deep-reverse (car c))
                        (car c)) r) (cdr c))))
  (iter nil src))
;(m-deep-reverse (list (list 1 2)))

(define (m-frange src)
  (define (iter r c)
    (if (null? c)
        r
        (iter (if (pair? (car c))
                  (iter r (car c))
                  (append r (list (car c))))
              (cdr c))))
  (iter nil src))
;(m-frange (list (list 1 2) 5 8 (list 3 4)))
(define (frange c)
  (cond ((null? c) nil)
        ((not (pair? c)) (list c))
        (else (append (frange (car c)) (frange (cdr c))))))
;(frange (list (list 1 2) (list 3 4)))
                          
(define (make-node left right)
  (list left right))

(define (make-branch length structure)
  (list length structure))

(define (left-branch node)
  (car node))
(define (right-branch node)
  (car (cdr node)))
(define (branch-length node)
  (car node))
(define (branch-structure node)
  (car (cdr node)))

(define (g-total-weight node)
  (if (pair? node)
      (if (pair? (branch-structure node))         
           (+ (g-total-weight (left-branch node))
             (g-total-weight (right-branch node)))
          (branch-structure node))
      0))
(define x1 (make-node
            (make-branch 2
                         (make-node
                            (make-branch 2 1)
                            (make-branch 1
                                         (make-node (make-branch 2 1) (make-branch 2 1)))))
                            (make-branch 2 3)))
(define x2 (make-node (make-branch 2 5) (make-branch 2 5))) 
;(total-weight x)
;(branch-structure (left-branch x))
(define (branch-power node)
  (* (branch-length node) (g-total-weight node)))

(define (node-blance? node)
   (if (pair? (branch-structure node))
       (= (branch-power (left-branch (branch-structure node)))
          (branch-power (right-branch (branch-structure node))))
       true))

(define (blance? node)
  (define (iter child)
    (if (pair? (branch-structure child))
        (and (iter (left-branch (branch-structure child)))
             (iter (right-branch (branch-structure child)))
             (node-blance? child))
        true))
  (and (= (branch-power (right-branch node)) (branch-power (left-branch node)))
       (iter (right-branch node)) (iter (left-branch node))))

;(node-blance? x1)
;(node-blance? (left-branch x1))
;(node-blance? (left-branch (branch-structure (left-branch x1))))

(blance? x1)

(define (h-square-tree tree)
  (map (lambda (t)
         (if (pair? t)
              (h-square-tree t)
              (* t t)))
       tree))

;(h-square-tree x1)

(define (l-square-tree tree)
  (cond ((null? tree) nil)
        ((not (pair? tree)) (* tree tree))
        (else (cons (l-square-tree (car tree)) (l-square-tree (cdr tree))))))

;(l-square-tree x1)
(define (tree-map func tree)
  (map (lambda (t)
         (if (pair? t)
             (cx-square-tree t)
             (func t)))
       tree))
(define (cx-square-tree tree)
  (tree-map square tree))
;(cx-square-tree x1)

(define (subset s)
  (if (null? s)
      (list nil)
      (let ((rest (subset (cdr s))))
        (append rest (map (lambda (x) (cons (car s) x)) rest)))))
(subset (list 1 2 3))